package view.GUI.sidepanels;

import controller.Constants;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import model.graphic.GraphicModel;
import model.graphic.objects.AbstractInPort;
import model.graphic.objects.AbstractOutPort;
import model.graphic.objects.Attachment;
import model.graphic.objects.GBoxNode;
import model.graphic.objects.GNode;
import model.graphic.objects.GResizeHandle;
import model.graphic.objects.GTransmitterNode;
import model.graphic.objects.Graphical;
import view.GUI.LabelReader;

/**
 *
 * @author Ben
 */
public class InventoryPanelModel extends DefaultTreeModel{
    private GraphicModel gmodel;

    public InventoryPanelModel(GraphicModel gmodel) {
        super(new DefaultMutableTreeNode(LabelReader.getInstance().getString("Grid")));
        this.gmodel = gmodel;
    }

    private Set<Graphical> getPortsFromGNode(GNode parent){
       Set<Graphical> graphs = gmodel.getAttachedObjects(parent,Constants.getPortsString());
       //remove the GResizeHandle
       return (Set<Graphical>)removeResizeHandles(graphs);
    }

    private Collection<Graphical> removeResizeHandles(Collection<Graphical> coll){
        ArrayList<Graphical> resizers = new ArrayList<Graphical>();
        for(Graphical g:  coll){
            if(g.getClass().isAssignableFrom(GResizeHandle.class)){
                resizers.add(g);
            }
        }
        coll.removeAll(resizers);
        return coll;
    }

    private ArrayList<Graphical> getBoxNodeObjects(GBoxNode box){
        //add the internal nodes and boxnodes
        ArrayList<Graphical> onlyNodes = new ArrayList<Graphical>();
        for(Graphical g: box.getInternalObjects()){
            if(g.getClass().isAssignableFrom(GNode.class)
            || g.getClass().isAssignableFrom(GBoxNode.class)){
                   onlyNodes.add(g);
            }
        }
        //remove the GResizeHandles from the internal nodes
        onlyNodes = (ArrayList<Graphical>)removeResizeHandles(onlyNodes);
        //add the outer side of the transmitter nodes
        for(Graphical g: box.getTransmitterObjects()){
            if(Attachment.class.isAssignableFrom(g.getClass())){
                Graphical base = ((Attachment)g).getBase();
                if(base.getClass().isAssignableFrom(GTransmitterNode.class)){
                   //adding is based on left or right position of the transmitter + type of g
                   if( (((GTransmitterNode)base).isLeft()
                          && AbstractInPort.class.isAssignableFrom(g.getClass()))
                       || (!((GTransmitterNode)base).isLeft()
                          && AbstractOutPort.class.isAssignableFrom(g.getClass()))){
                        onlyNodes.add(g);
                    }
                }
            }
        }
        return onlyNodes;
   }

    @Override
    public Object getChild(Object parent, int index) {
        if(parent.getClass().isAssignableFrom(GNode.class)){
          return getPortsFromGNode((GNode)parent).toArray()[index];
        }else if(parent == this.getRoot()){
          return gmodel.getAllNodes().get(index);
        }else if(parent.getClass().isAssignableFrom(GBoxNode.class)){
          return getBoxNodeObjects((GBoxNode)parent).get(index);
        }else{
          return "ERROR";
        }
    }

    @Override
    public int getChildCount(Object parent) {
        int size = 0;
        if(parent.getClass().isAssignableFrom(GNode.class)){
          size =  getPortsFromGNode((GNode)parent).size();
        }else if(parent == this.getRoot()){
          size =  gmodel.getAllNodes().size();
        }else if(parent.getClass().isAssignableFrom(GBoxNode.class)){
          size =  getBoxNodeObjects((GBoxNode)parent).size();
        }
        return size;
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        int index = 0;
        if(parent.getClass().isAssignableFrom(GNode.class)){
          Iterator<Graphical> it = getPortsFromGNode((GNode)parent).iterator();
          while(it.hasNext() && it.next() != child){
            index++;
          }
        }else if(parent == this.getRoot()){
          ArrayList<Graphical> nodes = gmodel.getAllNodes();
          while(index < nodes.size() && nodes.get(index) != child){
              index++;
          }
        }else if(parent.getClass().isAssignableFrom(GBoxNode.class)){
          ArrayList<Graphical> internals = getBoxNodeObjects((GBoxNode)parent);
          while(index < internals.size() && internals.get(index) != child){
              index++;
          }          
        }
        return index;
    }

    @Override
    public boolean isLeaf(Object parent) {
        return getChildCount(parent) == 0;
    }

}
